<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        
    </style>
</head>
<body>
    
</body>
<script>
    // 模拟事件监听式绑定和删除事件

    class MyEvent{
        constructor(){
            // 用来记录所有的事件和事件处理函数
            this.message = {};
        }
        add(type, cb){
            // 判断是否具有该事件，有就push，没有就添加
            if(this.message[type]){
                this.message[type].push(cb);
            }else{
                this.message[type] = [cb]
            }
        }
        remove(type, cb){
            // 判断是否存在该事件，不存在，直接结束
            if(!this.message[type]) return;
            // 准备从该事件的事件处理函数数组中找到当前要删除的事件处理函数
            let i;
            const flag = this.message[type].some((val,idx)=>{
                i = idx;
                return val === cb;
            })
            // 找到了
            if(flag){
                // 删除该事件处理函数
                this.message[type].splice(i ,1);
            }
        }
        emit(type){
            // 判断是否存在该事件，不存在，直接结束
            if(!this.message[type]) return;
            // 遍历当前事件的所有事件处理函数，执行
            this.message[type].forEach(val => {
                val();
            });
        }
    }

    const e = new MyEvent();

    function fn1(){
        console.log("这是事件处理函数1")
    }
    function fn2(){
        console.log("这是事件处理函数2")
    }
    function fn3(){
        console.log("这是事件处理函数3")
    }

    // 绑定事件（添加订阅者）
    e.add("abc", fn1)
    e.add("abc", fn2)

    e.add("xyz", fn1)

    // 删除事件（取消订阅）
    e.remove("abc", fn3)
    e.remove("asd", fn1)
    e.remove("abc", fn1)
    e.remove("abc", fn2)
    e.remove("xyz", fn2)
    e.remove("xyz", fn1)

    // 触发事件（发布事件行为）
    e.emit("abc");
    e.emit("xyz");

    console.log(e)

    // 打包数据时，对象或数组，怎么选？
    // 对象：非同类数据
    // 数组：同类数据


</script>
</html>